﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using WordRacer.Domain.Model.Boards.Exceptions;
using WordRacer.Domain.Model.GameCells;
using WordRacer.Domain.Model.Dictionaries;

namespace WordRacer.Domain.Model.Boards
{
  public class Board
  {
#if DEBUG
    private TimeSpan wordAlreadyFoundTimeUsage;
    private TimeSpan validWordTimeUsage;
    private TimeSpan possibleFutureWordTimeUsage;
#endif
    private IList<GameCell> boardCells;
    private IGameDictionary _gameDictionary { get; set; }
    private IList<string> foundWords;

    public Board()
    {
      boardCells = new List<GameCell>();
      foundWords = new List<string>();
      _gameDictionary = new Dictionaries.GameDictionary();
    }

    public Board(IGameDictionary gameDictionary)
    {
      boardCells = new List<GameCell>();
      foundWords = new List<string>();
      _gameDictionary = gameDictionary;
    }

    public IList<GameCell> GetBoardCells()
    {
      return boardCells;
    }

    public void AddGameCell(GameCell newCell)
    {
      if (!boardCells.Contains(newCell))
      {
        boardCells.Add(newCell);
      }
    }

    public void ConnectTwoCells(GameCell left, GameCell right)
    {
      if (boardCells.Contains(left) && boardCells.Contains(right))
      {
        GameCellHelper.ConnectTwoCells(left, right);
      }

      if (!boardCells.Contains(left))
      {
        throw new BoardOperationException("Left Cell not on the board yet.");
      }

      if (!boardCells.Contains(right))
      {
        throw new BoardOperationException("Right Cell not on the board yet.");
      }
    }

    public IList<string> GetWordsFoundInBoardUsingDictionary()
    {
#if DEBUG
      var dStamp = DateTime.Now;
      Console.Out.WriteLine("GetWordsFoundInBoardUsingDictionary:start:" + dStamp.ToString());
#endif
      ResetFoundWords();
      BuildWordsFromBoardAndDictionary();
#if DEBUG
      Console.Out.WriteLine("GetWordsFoundInBoardUsingDictionary:finish:" + (DateTime.Now - dStamp).ToString());
#endif
      return GetFoundWords();
    }

    private void BuildWordsFromBoardAndDictionary()
    {
      string currentWord = String.Empty;
      //loop through each cell as the starting point
#if DEBUG
      var lastStamp = DateTime.Now;
#endif
      foreach (var starterCell in this.boardCells)
      {
        if (starterCell.Character.ToUpper() == "Q")
        {
          currentWord = "QU";
        }
        else
        {
          currentWord = starterCell.Character.ToUpper();
        }
        starterCell.InUse = true;
#if DEBUG
        Console.Out.WriteLine("Startingletter: " + currentWord + ":" + (DateTime.Now - lastStamp).ToString());
        lastStamp = DateTime.Now;
#endif
        GetNextCell(starterCell, currentWord);
        starterCell.InUse = false;
      }
#if DEBUG
      Console.Out.WriteLine("wordAlreadyFoundTimeUsage:" + wordAlreadyFoundTimeUsage.ToString());
      Console.Out.WriteLine("validWordTimeUsage:" + validWordTimeUsage.ToString());
      Console.Out.WriteLine("possibleFutureWordTimeUsage:" + possibleFutureWordTimeUsage.ToString());
#endif
    }

    private void GetNextCell(GameCell currentCell, string inWord)
    {
      string currentWord;// = inWord;
      foreach (var nextCell in currentCell.ConnectedCells)
      {
        currentWord = inWord;
        if (!nextCell.InUse)
        {
          if (nextCell.Character.ToUpper() == "Q")
          {
            currentWord += "QU";
          }
          else
          {
            currentWord += nextCell.Character.ToUpper();
          }
          nextCell.InUse = true;
          if (!WordAlreadyFound(currentWord))
          {
            if (validWord(currentWord))
            {
              AddFoundWord(currentWord);
            }
          }
          if (possibleFutureWord(currentWord))
          {
            GetNextCell(nextCell, currentWord);
          }
          nextCell.InUse = false;
        }
      }
    }

    private void ResetFoundWords()
    {
      this.foundWords = new List<string>();
    }

    private IList<string> GetFoundWords()
    {
      return this.foundWords;
    }

    private void AddFoundWord(string foundWord)
    {
      this.foundWords.Add(foundWord);
    }

    private bool possibleFutureWord(string currentWord)
    {
#if DEBUG
      var start = DateTime.Now;
#endif
      var ret = _gameDictionary.possibleFutureWord(currentWord);
#if DEBUG
      possibleFutureWordTimeUsage += DateTime.Now - start;
#endif
      return ret;
    }

    private bool validWord(string testWord)
    {
#if DEBUG
      var start = DateTime.Now;
#endif
      var ret =  _gameDictionary.Contains(testWord);
#if DEBUG
      validWordTimeUsage += DateTime.Now - start;
#endif
      return ret;
    }

    private bool WordAlreadyFound(string testWord)
    {
#if DEBUG
      var start = DateTime.Now;
#endif
      var ret = foundWords.Contains(testWord);
#if DEBUG
      wordAlreadyFoundTimeUsage += DateTime.Now - start;
#endif
      return ret;
    }
  }
}
